我們在「為縮放魔法設置疆界」中展示了等比縮放產生的畫面過大問題,並學會如何限制 vw 的數值成長。
如果想避免 vw 數值無限制的放大或縮小,可以使用 max() 與 min() 來限制:
min( 設計稿上的值px, calc( 設計稿上的值 / 設計稿寬度 * 100vw )) 公式來限制數值放大。max( 設計稿上的值px, calc( 設計稿上的值 / 設計稿寬度 * 100vw )) 公式來限制數值縮小。有了這兩個公式,我們就能修改「實戰1」的程式碼來解決無限制縮放畫面的問題了~
只要把「實戰1」那一堆 calc( 設計稿上的值 / 設計稿寬度 * 100vw ) 公式全部改成上面兩個公式即可。
修改範例
   .square {
-    left: calc(-10 / 375 * 100vw);
-    width: calc(10 / 375 * 100vw);
-    height: calc(10 / 375 * 100vw);
+    left: max(-10px, calc(-10 / 375 * 100vw));
+    width: min(10px, calc(10 / 375 * 100vw));
+    height: min(10px, calc(10 / 375 * 100vw));
   }
為了版面乾淨,這邊就不全列了,可以到最下面看完整的程式碼。
結果

結果已經相當接近我們在「用等比縮放達到我心中的 pixel perfect」中所預期的目標效果了!
當視窗寬度大於設計稿寬度時,利用 min() 和 max() 讓畫面停止放大或縮小,當使用者的視窗畫面太大時,就不會感覺網站怎麼超爆大,使用體驗應該會比較舒服些。

細看第一天的展示效果可能會發現,左邊的圓圈在視窗超過 1440px 跟 375px 時,會直接固定在原地,但是右邊不會,這其實是為了呈現兩者不同而故意設計的。
absolute 盒子。100%。top:0 與置中。index.html
圓圈外加一層盒子。
- <div class="circle1"></div>
+ <div class="lock-box">
+   <div class="circle1"></div>
+ </div>
src/normal.css
盒子最大只能與設計稿同寬,也就是 width: min(1440px, 100vw); 與 width: min(375px, 100vw);,並且依上述方式實現即可。
.lock-box {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, 0);
  width: min(1440px, 100vw);
  height: 100%;
}
@media (width < 768px) {
  .lock-box {
    width: min(375px, 100vw);
  }
}
效果

現在我們就完全實現了「用等比縮放達到我心中的 pixel perfect」的目標效果,注意左邊圓圈的位置,當超出 1440px 與 375px 時,左邊圓圈就定在原地,相對於右邊圓圈的處理有明顯的不同。
下篇我們將介紹另一種更簡潔的延伸固定作法~那我們下篇見囉!
css/reset.css 與 index.html 可以去「實戰1」中複製,都沒變。src/normal.css
:root {
  --color-red: #C22A29;
}
html, body {
  overflow-x: hidden;
}
body {
  background-color: black;
  min-height: 100vh;
  min-height: 100dvh;
  color: white;
  font-family: "Noto Sans TC", sans-serif;
}
/* layout */
#app {
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  width: 100vw;
  overflow: hidden;
  padding: min(50px, calc(50 / 1440 * 100vw)) 0;
}
.container {
  width: min(1340px, calc(1340 / 1440 * 100vw));
  margin: auto;
  display: flex;
}
.box1 {
  margin-right: min(50px, calc(50 / 1440 * 100vw));
}
.box2 {
  flex: 1;
}
@media (width < 768px) {
  #app {
    padding: min(30px, calc(30 / 375 * 100vw)) 0;
  }
  .container {
    width: min(335px, calc(335 / 375 * 100vw));
    flex-direction: column;
    align-items: center;
  }
  .box1 {
    margin-right: 0;
    margin-bottom: min(20px, calc(20 / 375 * 100vw));
  }
}
/* album */
.album {
  width: max-content;
  background: var(--color-red);
  padding: min(50px, calc(50 / 1440 * 100vw));
  margin-bottom: min(50px, calc(50 / 1440 * 100vw));
}
.album-inner {
  position: relative;
  width: min(500px, calc(500 / 1440 * 100vw));
}
.album-inner::after {
  content: '';
  display: block;
  padding-top: 100%;
}
.album img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
@media (width < 768px) {
  .album {
    padding: min(20px, calc(20 / 375 * 100vw));
    margin-bottom: min(20px, calc(20 / 375 * 100vw));
  }
  .album-inner {
    width: min(260px, calc(260 / 375 * 100vw));
  }
}
/* info */
.info-box {
  padding-left: min(30px, calc(30 / 1440 * 100vw));
}
.square {
  position: absolute;
  top: 50%;
  left: max(-10px, calc(-10 / 1440 * 100vw));
  transform: translate3d(-100%,-50%,0);
  width: min(20px, calc(20 / 1440 * 100vw));
  height: min(20px, calc(20 / 1440 * 100vw));
  background-color: var(--color-red);
}
.song {
  position: relative;
  font-size: min(40px, calc(40 / 1440 * 100vw));
  font-weight: 700;
}
.singer {
  font-size: min(32px, calc(32 / 1440 * 100vw));
}
@media (width < 768px) {
  .info-box {
    padding-left: min(20px, calc(20 / 375 * 100vw));
  }
  .square {
    left: max(-10px, calc(-10 / 375 * 100vw));
    width: min(10px, calc(10 / 375 * 100vw));
    height: min(10px, calc(10 / 375 * 100vw));
  }
  .song {
    font-size: min(25px, calc(25 / 375 * 100vw));
  }
  .singer {
    font-size: min(18px, calc(18 / 375 * 100vw));
  }
}
/* lyrics */
.lyrics {
  font-size: min(28px, calc(28 / 1440 * 100vw));
}
@media (width < 768px) {
  .lyrics {
    font-size: min(14px, calc(14 / 375 * 100vw));
  }
}
/* circle */
.circle1 {
  position: absolute;
  top: min(862px, calc(862 / 1440 * 100vw));
  left: max(-100px, calc(-100 / 1440 * 100vw));
  width: min(200px, calc(200 / 1440 * 100vw));
  height: min(200px, calc(200 / 1440 * 100vw));
  border-radius: 50%;
  background-color: var(--color-red);
}
.circle2 {
  position: absolute;
  top: min(50px, calc(50 / 1440 * 100vw));
  right: max(-50px, calc(-50 / 1440 * 100vw));
  width: min(100px, calc(100 / 1440 * 100vw));
  height: min(100px, calc(100 / 1440 * 100vw));
  background: var(--color-red);
  border-radius: 50%;
}
@media (width < 768px) {
  .circle1 {
    top: max(-25px, calc(-25 / 375 * 100vw));
    left: max(-25px, calc(-25 / 375 * 100vw));
    width: min(50px, calc(50 / 375 * 100vw));
    height: min(50px, calc(50 / 375 * 100vw));
  }
  .circle2 {
    top: min(362px, calc(362 / 375 * 100vw));
    right: max(-50px, calc(-50 / 375 * 100vw));
    width: min(100px, calc(100 / 375 * 100vw));
    height: min(100px, calc(100 / 375 * 100vw));
  }
}